package com.gxar.marketdelivery.application.facade;

import com.gxar.marketdelivery.domain.enums.DeliveryResSlotStatus;
import com.gxar.marketdelivery.domain.factory.DeliveryFactory;
import com.gxar.marketdelivery.domain.repo.DeliveryPlanRepository;
import com.gxar.marketdelivery.domain.repo.DeliveryResSlotRepository;
import com.gxar.marketdelivery.domain.validator.SchemaValidator;
import com.gxar.marketdelivery.infra.dao.entity.DeliveryPlanEntity;
import com.gxar.marketdelivery.infra.dao.entity.DeliveryResSlotEntity;
import com.gxar.marketdelivery.interfaces.assembler.DeliveryResSlotConverter;
import com.gxar.marketdelivery.interfaces.web.param.BaseIdParam;
import com.gxar.marketdelivery.interfaces.web.param.CreateDeliveryResSlotParam;
import com.gxar.marketdelivery.interfaces.web.param.LongIdsParam;
import com.gxar.marketdelivery.interfaces.web.param.QueryDeliveryResSlotParam;
import com.gxar.marketdelivery.interfaces.web.param.UpdateDeliveryResSlotParam;
import com.gxar.marketdelivery.interfaces.web.result.CommonPageResult;
import com.gxar.marketdelivery.interfaces.web.result.DeliveryResSlotResult;
import com.gxar.marketdelivery.interfaces.web.result.IResponseStatusMsg;
import com.gxar.marketdelivery.shared.model.DeliveryResSlotModel;
import com.gxar.marketdelivery.shared.model.OpInfo;
import com.gxar.marketdelivery.shared.utils.AssemblerUtils2;
import com.gxar.marketdelivery.shared.utils.AssertUtils;
import com.gxar.marketdelivery.shared.utils.CollectionUtils;
import com.gxar.marketdelivery.shared.utils.ExtractUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@Slf4j
public class DeliveryResSlotFacade {

    @Autowired
    protected DeliveryResSlotRepository deliveryResSlotRepository;
    @Autowired
    protected DeliveryPlanRepository deliveryPlanRepository;
    @Autowired
    protected DeliveryFactory deliveryFactory;

    @Transactional(rollbackFor = Exception.class)
    public void create(CreateDeliveryResSlotParam param) {
        validateMaterial(param);
        DeliveryResSlotEntity oldEntity = deliveryResSlotRepository.getByKey(param.getResSlotKey());
        AssertUtils.isNull(oldEntity, IResponseStatusMsg.APIEnum.PARAM_ERROR, "资源位Key已存在");
        OpInfo opInfo = OpInfo.SYS_OP;
        deliveryFactory.createResSlot(param, opInfo);
    }

    @Transactional(rollbackFor = Exception.class)
    public void update(UpdateDeliveryResSlotParam param) {
        validateMaterial(param);
        OpInfo opInfo = OpInfo.SYS_OP;
        DeliveryResSlotEntity entity = getAndCheck(param.getId());
        DeliveryResSlotEntity oldEntity = deliveryResSlotRepository.getByKey(param.getResSlotKey());
        if (oldEntity != null) {
            AssertUtils.isTrue(oldEntity.getId().equals(entity.getId()), IResponseStatusMsg.APIEnum.PARAM_ERROR,
                    "资源位Key已存在");
        }
        deliveryFactory.updateResSlot(param, entity, opInfo);
    }

    private void validateMaterial(DeliveryResSlotModel resSlotModel) {
        if (resSlotModel.getMaterialModel() != null) {
            AssertUtils.notNull(resSlotModel.getMaterialModel(), IResponseStatusMsg.APIEnum.PARAM_ERROR,
                    "投放物料不能为空");
            SchemaValidator.validateMaterial(resSlotModel.getResSlotStaticSchema(), resSlotModel.getMaterialModel());
        }
    }

    public void open(BaseIdParam param) {
        OpInfo opInfo = OpInfo.SYS_OP;
        DeliveryResSlotEntity entity = getAndCheck(param.getId());
        AssertUtils.isTrue(DeliveryResSlotStatus.CLOSE.equalByCode(entity.getResSlotStatus()),
                IResponseStatusMsg.APIEnum.PARAM_ERROR, "该资源位已经是开启状态");

        DeliveryResSlotEntity updateEntity = new DeliveryResSlotEntity();
        updateEntity.setModifier(opInfo.getOpId());
        updateEntity.setId(param.getId());
        updateEntity.setResSlotStatus(DeliveryResSlotStatus.OPEN.getCode());
        deliveryResSlotRepository.updateNotNull(updateEntity);
        // 刷新缓存
        DeliveryResSlotModel resSlotModel = deliveryFactory.getResSlot(entity.getId());
        AssertUtils.notNull(resSlotModel, IResponseStatusMsg.APIEnum.PARAM_ERROR, "资源位不存在");
        resSlotModel.setResSlotStatus(updateEntity.getResSlotStatus());
        List<DeliveryPlanEntity> planEntities = deliveryPlanRepository.getOnlineByResSlotId(entity.getId());
        List<Long> planIds = ExtractUtils.extractField(planEntities, DeliveryPlanEntity::getId);
    }

    public void close(BaseIdParam param) {
        OpInfo opInfo = OpInfo.SYS_OP;
        DeliveryResSlotEntity entity = getAndCheck(param.getId());
        AssertUtils.isTrue(DeliveryResSlotStatus.OPEN.equalByCode(entity.getResSlotStatus()),
                IResponseStatusMsg.APIEnum.PARAM_ERROR, "该资源位已经是关闭状态");
        DeliveryResSlotEntity updateEntity = new DeliveryResSlotEntity();
        updateEntity.setModifier(opInfo.getOpId());
        updateEntity.setId(param.getId());
        updateEntity.setResSlotStatus(DeliveryResSlotStatus.CLOSE.getCode());
        deliveryResSlotRepository.updateNotNull(updateEntity);
    }

    public DeliveryResSlotResult getDetail(BaseIdParam param) {
        DeliveryResSlotModel resSlotModel = deliveryFactory.getResSlot(param.getId());
        if (resSlotModel == null) {
            return null;
        }
        DeliveryResSlotResult resSlotResult = new DeliveryResSlotResult();
        AssemblerUtils2.assemble(resSlotModel, resSlotResult);
        resSlotResult.setId(String.valueOf(resSlotModel.getId()));
        resSlotResult.setMaterialModel(resSlotModel.getMaterialModel());
        return resSlotResult;
    }

    public CommonPageResult<DeliveryResSlotResult> getPageList(QueryDeliveryResSlotParam param) {
        CommonPageResult<DeliveryResSlotResult> pageResult = new CommonPageResult<>();
        pageResult.setPageSize(param.getPageSize());
        pageResult.setPageNow(param.getPageNow());
        Integer totalCount = deliveryResSlotRepository.getPageCount(param);
        pageResult.setCount(totalCount.longValue());
        if (totalCount < 1) {
            pageResult.setList(Collections.emptyList());
        } else {
            List<DeliveryResSlotEntity> entities = deliveryResSlotRepository.getPageList(param);
            pageResult.setList(DeliveryResSlotConverter.convertToResultList(entities));
        }
        return pageResult;
    }

    public Map<Long, String> multiGetPlanStaticSchema(LongIdsParam param) {
        List<DeliveryResSlotEntity> resSlotEntities = deliveryResSlotRepository.getByIds(param.getIds());
        if (CollectionUtils.isEmpty(resSlotEntities)) {
            return Collections.emptyMap();
        }
        return resSlotEntities.stream()
                .collect(Collectors.toMap(DeliveryResSlotEntity::getId, DeliveryResSlotEntity::getPlanStaticSchema));
    }

    private DeliveryResSlotEntity getAndCheck(Long id) {
        DeliveryResSlotEntity entity = deliveryResSlotRepository.getById(id);
        AssertUtils.notNull(entity, IResponseStatusMsg.APIEnum.PARAM_ERROR, "该投放组不存在或已删除");
        return entity;
    }

}
